package com.petshop.service.impl;

import cn.hutool.core.util.BooleanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.petshop.dto.QueryPostDTO;
import com.petshop.mapper.PostsMapper;
import com.petshop.pojo.Follow;
import com.petshop.pojo.Posts;
import com.petshop.pojo.Users;
import com.petshop.service.FollowService;
import com.petshop.service.PostsService;
import com.petshop.service.UsersService;
import com.petshop.utils.Result;
import com.petshop.utils.UserHolder;
import com.petshop.vo.PostDetailVO;
import com.petshop.vo.ScrollResult;
import jakarta.annotation.Resource;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.core.ZSetOperations;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.*;

/**
 * @author 20289
 * &#064;description  针对表【posts(存储用户发布的帖子信息)】的数据库操作Service实现
 * &#064;createDate  2025-02-27 11:17:00
 */
@Service
public class PostsServiceImpl extends ServiceImpl<PostsMapper, Posts>
        implements PostsService {

    @Resource
    private PostsMapper postsMapper;
    @Resource
    private FollowService followService;
    @Resource
    private UsersService usersService;
    @Resource
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 删除一条帖子（根据id）
     *
     */
    @Override
    public Result deletePost(Integer postId) {
        LambdaQueryWrapper<Posts> lambdaQueryWrapper =
                new LambdaQueryWrapper<>();
        lambdaQueryWrapper.eq(Posts::getPostId, postId);
        Long count = postsMapper.selectCount(lambdaQueryWrapper);
        if (count > 0) {
            //帖子存在，删除
            postsMapper.deleteById(postId);
            return Result.ok("删除成功！");
        }
        return Result.error("删除失败！");
    }

    /**
     * 修改帖子
     *
     */
    @Override
    public Result updatePost(Posts posts) {
        Integer version = posts.getVersion();
        //添加乐观锁
        posts.setVersion(version);
        //更新修改时间
        // 设置更新时间为当前时间（东八区），精确到秒
        LocalDateTime now = LocalDateTime.now(ZoneId.of("Asia/Shanghai"));
        Instant instant = now.atZone(ZoneId.of("Asia/Shanghai")).toInstant();
        Date date = Date.from(instant);
        posts.setUpdatedAt(date);
        int i = postsMapper.updateById(posts);
        if (i > 0)
            return Result.ok(null);
        else
            return Result.error(null);
    }

    //查询发帖用户的函数
    public Users getPostUser(Posts posts) {
        Integer userId = posts.getUserId();
        return usersService.getById(userId);
    }
    /**
     * 根据帖子id查询帖子
     *
     */
    @Override
    public Result queryPostById(Integer postId) {
        //查询帖子
        Posts posts = getById(postId);
        if (posts == null) {
            return Result.error("帖子不存在！");
        }
        //查询发帖用户
        Users postUser = getPostUser(posts);
        //查询当前post有没有被当前用户点赞
        isPostLiked(posts);
        //存入vo对象里
        PostDetailVO postDetailVO = new PostDetailVO();
        postDetailVO.setPosts(posts);
        postDetailVO.setUser(postUser);
        return Result.ok(postDetailVO);
    }

    //用来获知当前用户对这个帖子有没有点过赞，点过就把帖子的isLike字段赋值为true，反之false
    private void isPostLiked(Posts posts) {
        //1.获取当前用户id
        Integer userId = UserHolder.getUser().getUserId();
        //2.首先判断当前登录用户是否点赞
        String key = "post:liked:" + posts.getPostId();
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        posts.setIsLike(BooleanUtil.isTrue(isMember));
    }

    /**
     * 获取帖子列表
     *
     */
    @Override
    public Result getPostList(QueryPostDTO queryPostDTO) {
        Page<Posts> page = new Page<>(queryPostDTO.getPageCount(), queryPostDTO.getPageSize());
        LambdaQueryWrapper<Posts> lambdaQueryWrapper
                = new LambdaQueryWrapper<>();
        Page<Posts> postsPage;
        if (queryPostDTO.getContent().isEmpty()) {
            //什么都没传入，则无条件分页查询
            postsPage = postsMapper.selectPage(page, null);
        } else {
            //对传入的内容进行标题和内容的模糊查询
            lambdaQueryWrapper
                    .like(Posts::getContent, queryPostDTO.getContent())
                    .or()
                    .like(Posts::getTitle, queryPostDTO.getContent());
            postsPage = postsMapper.selectPage(page, lambdaQueryWrapper);
        }
        return Result.ok(postsPage);
    }

    /**
     * 仅查询第一页帖子
     *
     */
    @Override
    public Result getFirstPost(QueryPostDTO queryPostDTO) {
        Page<Posts> page = new Page<>(1, queryPostDTO.getPageSize());
        LambdaQueryWrapper<Posts> lambdaQueryWrapper
                = new LambdaQueryWrapper<>();
        Page<Posts> postsPage;
        if (queryPostDTO.getContent().isEmpty()) {
            //什么都没传入，则无条件分页查询
            postsPage = postsMapper.selectPage(page, null);
        } else {
            //对传入的内容进行标题和内容的模糊查询
            lambdaQueryWrapper
                    .like(Posts::getContent, queryPostDTO.getContent())
                    .or()
                    .like(Posts::getTitle, queryPostDTO.getContent());
            postsPage = postsMapper.selectPage(page, lambdaQueryWrapper);
        }
        return Result.ok(postsPage);
    }

    /**
     * 获取帖子详情，点赞数，评论数，发帖人
     *
     * @param postId
     * @param token
     * @return
     */
    @Override
    public Result getPostDetail(Integer postId, String token) {
        PostDetailVO postDetailVO = new PostDetailVO();
        //1.查询帖子
        Posts posts = getById(postId);
        if (posts == null) {
            return Result.error("帖子已经被删除！");
        }
        postDetailVO.setPosts(posts);
        //2.查询发帖子的用户
        Users postUser = getPostUser(posts);
        postDetailVO.setUser(postUser);
        return Result.ok(postDetailVO);
    }

    /**
     * 点赞&取消点赞
     *
     * @param postId
     * @return
     */
    @Override
    public Result likePost(Integer postId) {
        //1.获取当前用户id
        Integer userId = UserHolder.getUser().getUserId();
        //2.首先判断当前登录用户是否点赞
        String key = "post:liked:" + postId;
        Boolean isMember = stringRedisTemplate.opsForSet().isMember(key, userId.toString());
        if (BooleanUtil.isFalse(isMember)) {
            //3.如果未点赞，则点赞
            //3.1 数据库点赞数+1
            boolean isSuccess = update().setSql("liked = liked +1").eq("post_id", postId).update();
            if (isSuccess) {
                //3.2 保存用户的id到redis的Set集合
                stringRedisTemplate.opsForSet().add(key, userId.toString());
            }
        } else {
            //4.如果已经点赞，则取消点赞
            //4.1数据库点赞数-1
            boolean isSuccess = update().setSql("liked = liked -1").eq("post_id", postId).update();
            //4.2把用户id从redis的set集合里移除
            if (isSuccess) {
                stringRedisTemplate.opsForSet().remove(key, userId.toString());
            }
        }
        return Result.ok(null);
    }

    /**
     * 增加一条帖子
     */
    @Override
    public Result insertPost(Posts posts) {
        //1.获取用户id
        Integer userId = UserHolder.getUser().getUserId();
        posts.setUserId(userId);
        //2.保存帖子
        boolean isSave = save(posts);
        if (!isSave) {
            return Result.error("发布失败！请重试！");
        }
        //3.查询作者有哪些粉丝 select * from tb_follow where follow_user_id= ?
        List<Follow> follows = followService.lambdaQuery().eq(Follow::getFollowUserId, userId).list();
        //4.推送帖子给粉丝
        for (Follow follow : follows) {
            //4.1获取粉丝id
            Long funId = follow.getUserId();
            //4.2推送帖子到收件箱，也就是ZSet里。格式：key：feed:粉丝id(userId) value：postId,发布时间
            String key = "feed:"+funId;
            stringRedisTemplate.opsForZSet().add(key,posts.getPostId().toString(),System.currentTimeMillis());
        }
        return Result.ok(posts.getPostId());
    }

    /**
     * 滚动查询关注的人的帖子
     *
     */
    @Override
    public Result queryFollowPost(Long max, Integer offset) {
        //1.获取当前用户
        Integer userId = UserHolder.getUser().getUserId();
        //2.查询收件箱
        String key = "feed:" + userId;
        //2.1滚动分页查询 ZREVRANGEBYSCORE key max min limit offset count
        Set<ZSetOperations.TypedTuple<String>> typedTuples =
                stringRedisTemplate.opsForZSet()
                .reverseRangeByScoreWithScores(key, 0, max, offset, 4);
        if (typedTuples==null||typedTuples.isEmpty())  return  Result.ok(null);
        //3.原本数据格式：key：feed:粉丝id(userId) value：postId,发布时间
        //  解析数据成postId、minTime发布时间（可作为score）、offset
        //保存帖子的id们
        List<Integer> ids = new ArrayList<>(typedTuples.size());
        long minTime = 0L;
        int offs = 1;
        for (ZSetOperations.TypedTuple<String> typedTuple : typedTuples) {
            //获取帖子id字符串
            String idStr = typedTuple.getValue();
            if (idStr != null) {
                ids.add(Integer.parseInt(idStr));
            }
            //获取帖子的发布时间、获取offset
            long time = Objects.requireNonNull(typedTuple.getScore()).longValue();
            //检查有几个score是和当前最小时间相等的
            if(time == minTime){
                //相等offset++
                offs++;
            }else{
                //不相等，说明还有更小的score，重置offset
                minTime= time;
                offs=1;
            }
        }
        //4.根据id查询post
        List<Posts> postsList =null;
        for (Integer id : ids) {
            Posts post = getById(id);
            //查询当前post有没有被当前用户点赞
            isPostLiked(post);
            //加入集合
            postsList.add(post);
        }
        //5.封装帖子、最小值minTime、偏移量offset 返回
        ScrollResult scrollResult = new ScrollResult();
        scrollResult.setList(postsList);
        scrollResult.setMinTime(minTime);
        scrollResult.setOffset(offs);
        return Result.ok(scrollResult);
    }

}




